"""
python p2_solution_simanneal_Annealer_4t.py
"""

import json
import os
import random
import time
from datetime import datetime
from simanneal import Annealer
import signal

# 信号处理
def signal_handler(sig, frame):
    print("接收到中断信号，停止迭代...")
    raise KeyboardInterrupt

signal.signal(signal.SIGINT, signal_handler)

# 数据文件的相对路径
WAREHOUSE_FILE = '../fujian/fujian3/origin_data/warehouse.json'
INVENTORY_FILE = '../fujian/fujian3/data_from_p1/all_average_inventory.json'
SALES_FILE = '../fujian/fujian3/data_from_p1/all_average_sales.json'
ASSOCIATION_FILE = '../fujian/fujian4/origin_data.json'
INITIAL_SOLUTION_FILE = '../fujian/p2/simple_solution_handwrite/ans.json'

# 输出文件路径
OUTPUT_DIR = '../fujian/fujian3/simanneal_Annealer_4t/best_ever'
os.makedirs(OUTPUT_DIR, exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
BEST_T_FILE = os.path.join(OUTPUT_DIR, f'best_t_{timestamp}.log')
BEST_SOLUTION_FILE = os.path.join(OUTPUT_DIR, 'best_solution.json')

class WarehouseOptimization(Annealer):
    def __init__(self, initial_state, warehouses, inventories, sales, associations):
        super().__init__(initial_state)
        self.warehouses = warehouses
        self.inventories = inventories
        self.sales = sales
        self.associations = associations
        self.best_t_values = None
        print(warehouses)

    def move(self):
        # 随机改变某个类别的仓库分配，以探索邻近解
        category = random.choice(list(self.state.keys()))
        available_warehouses = list(self.warehouses.keys())
        self.state[category] = random.choice(available_warehouses)

    def energy(self):
        # 计算当前解的适配度（fitness）及目标值t1, t2, t3, t4
        t1, t2, t3, t4 = 0, 0, 0, 0

        for warehouse_id, warehouse_info in self.warehouses.items():
            warehouse_inventory = sum(
                self.inventories[category] for category, assigned_warehouse in self.state.items()
                if assigned_warehouse == warehouse_id and category in self.inventories
            )
            warehouse_sales = sum(
                self.sales[category] for category, assigned_warehouse in self.state.items()
                if assigned_warehouse == warehouse_id and category in self.sales
            )

            # print(f"Warehouse {warehouse_id} Inventory: {warehouse_inventory}")
            # print(f"Warehouse {warehouse_id} Sales: {warehouse_sales}")

            # 检查库存和销售是否超过仓库的最大限制
            if warehouse_inventory > warehouse_info['max_inventory'] or \
                warehouse_sales > warehouse_info['max_sales']:
                return float('inf')  # 不合法解
            
            if warehouse_inventory > 0:
                t1 += warehouse_info['daily_cost']
                t2 += warehouse_inventory / warehouse_info['max_inventory']
                t3 += warehouse_sales / warehouse_info['max_sales']

        # 计算目标值t4
        t4 = sum(
            self.associations.get((category1, category2), 0)
            for category1, warehouse1 in self.state.items()
            for category2, warehouse2 in self.state.items()
            if category1 != category2 and warehouse1 == warehouse2
        )

        # 计算适配度
        fitness = t1 * t2 * t3 * t4
        print(f"t1: {t1}, t2: {t2}, t3: {t3}, t4: {t4}, fitness: {fitness}")

        # 保存最优解并写入文件
        if self.best_t_values is None or fitness < self.best_t_values[0]:
            self.best_t_values = (fitness, t1, t2, t3, t4)
            self.save_best_solution()
        return fitness

    def save_best_solution(self):
        # 保存当前最优解
        with open(BEST_SOLUTION_FILE, 'w') as f:
            json.dump(self.state, f, indent=4)
        with open(BEST_T_FILE, 'a') as f:
            f.write(f"{datetime.now()}: {self.best_t_values[1:]}\n")

# 加载数据
with open(WAREHOUSE_FILE, 'r') as f:
    warehouses = {w['warehouse_id']: w for w in json.load(f)}

with open(INVENTORY_FILE, 'r') as f:
    inventories = {item['category_id']: item['average_inventory'] for item in json.load(f)}

with open(SALES_FILE, 'r') as f:
    sales = {item['category_id']: item['average_sales'] for item in json.load(f)}

with open(ASSOCIATION_FILE, 'r') as f:
    raw_associations = json.load(f)
    associations = {
        (assoc['category1'], assoc['category2']): assoc['association'] for assoc in raw_associations
    }

with open(INITIAL_SOLUTION_FILE, 'r') as f:
    initial_solution_data = json.load(f)
    # 将每个元素转换为字典形式的 category_id: warehouse_id
    initial_solution = {int(list(item.keys())[0]): int(list(item.values())[0]) for item in initial_solution_data}

# 初始化模拟退火对象
problem = WarehouseOptimization(initial_solution, warehouses, inventories, sales, associations)
problem.copy_strategy = "deepcopy"  # 深拷贝策略，确保状态修改不影响历史记录

# 无限循环的退火过程
try:
    while True:
        problem.steps = 1000   # 每次迭代的步数，可以根据需要进行调整
        problem.Tmax = 25000   # 初始温度
        problem.Tmin = 2.5     # 最小温度

        best_solution, fitness = problem.anneal()
        # print("当前最佳解:", best_solution)
        print("当前适配度:", fitness)
except KeyboardInterrupt:
    print("迭代已被用户手动停止")
